/*
 * 2022/1/4	11:51	qing	
 */

/*
 * 目录结构	P240
 */


/*
 * 目录处理代码		P240
 */
	004019f0 sub esp, 8
	004019f3 push ebx
			 push ebp
			 push esi
			 mov esi, ss:[esp+18]
			 xor ebx, ebx
			 push ebx				; origin => FILE_BEGIN
			 push ebx				; pOffsetHi => NULL
			 push ebx				; OffsetLo => 0
			 push esi				; hFile
			 call SetFilePointer
			 push ebx				; pOverlapped => NULL
			 lea eax, ss:[esp+14]
			 push eax				; pBytesRead
			 push 28				; BytesToRead = 0x28 (40)
			 push cryptex.00406058	; Buffer = 00406058
			 push esi				; hFile
			 call ReadFile
			 mov ecx, ss:[esp+1c]
			 mov edx, ds:[406064]
			 push ecx
			 push edx
			 push esi
			 call 00401030
			 mov ebp, ds:[<printf>]
			 mov esi, ds:[406064]
			 push 00403234			; format = '' File Size File Name"
			 mov dword ptr ss:[esp+1c], cryptex.00405050
			 call ebp				; printf
			 add esp, 10
			 test esi, esi
			 je short cryptex.00401acd
			 push edi
			 mov edi, ss:[esp+24]
			 jmp short 00401a60
			 lea esp, ss:[esp]
			 lea esp, ss:[esp]
			 mov esi, ss:[esp+10]
			 add esi, 8
			 mov dword ptr ss:[esp+14], 1a
			 nop
			 mov eax, ds:[esi]
			 test eax, eax
			 je short 00401a9a
			 mov edx, eax
			 shl edx, 0a
			 sub edx, eax
			 add edx, edx
			 lea ecx, ds:[esi+14]
			 add edx, edx
			 push ecx
			 shr edx, 0a
			 push edx
			 push 00403250		; ASCII  " %l0dK   %s"
			 call ebp
			 mov eax, ds:[esi]
			 add ds:[edi], eax
			 add esp, 0c
			 add ebx, 1
			 add esi, 98
			 sub dword ptr ss:[esp+14], 1
			 jnz short 00401a70
			 mov ecx, ss:[esp+10]
			 mov esi, ds:[ecx]
			 test esi, esi
			 je short 00401acc
			 mov edx, ss:[esp+20]
			 mov eax, ss:[es[+1c]
			 push edx
			 push esi
			 push eax
			 call 00401030
			 add esp, 0c
			 test esi, esi
			 mov ss:[esp+10], eax
			 jnz short 00401a60
			 pop edi
			 pop esi
			 pop ebp
			 mov eax, ebx
			 pop ebx
			 add esp, 8
	00401AD5 retn

	将头部读入内存。从文件中偏移量 0 处开始读取了 0x28 个字节。

	00401030 处的反汇编代码:

	00401030 push ecx
	00401031 push esi
			 mov esi, ss:[esp+c]
			 push edi
			 mov edi, ss:[esp+14]
			 mov ecx, 1008
			 lea eax, ds:[edi-1]
			 mul ecx
			 add eax, 28
			 adc edx, 0
			 push 0					; Origin = FILE_BEGIN
			 mov ss:[esp+18], edx	
			 lea edx, ss:[esp+18]
			 push edx				; pOffsetHi
			 push eax				; OffsetLo
			 push esi				; hFile
			 call SetFilePointer
			 push 0					; pOverlapped = NULL
			 lea eax, ss:[esp+c]
			 push eax				; pBytesRead
			 push 1008				; BytesToRead = 1008 (4104)
			 push 00405050			; Buffer = 00405050
			 push esi				; hFile
			 call ReadFile
			 test eax, eax
			 je short 004010cb
			 mov eax, ss:[esp+18]
			 test eax, eax
			 mov dword ptr ss:[esp+14], 1008
			 je short 004010c2
			 lea ecx, ss:[esp+14]
			 push ecx
			 push 00405050
			 push 0
			 push 1
			 push 0
			 push eax
			 call CryptDecrypt
			 test eax, eax
			 jnz short 004010c2
			 call GetLastError
			 push edi				; <%d>
			 push 004030e8			; format = "error: unable to decrypt block from cluster %d."
			 call printf
			 add esp, 8
			 push 1					; status = 1
			 call exit
			 pop edi
			 mov eax, 00405050
			 pop esi
			 pop ecx
			 retn
			 pop edi
			 xor eax, eax
			 pop esi
			 pop ecx
			 retn
	从.crx文件中读取了一个固定大小(4104 字节)的数据块。

	这个读操作让人感到好奇的是: 它是怎样计算读操作的起始地址的。
	该函数接收了一个参数，该参数先乘以 4104 , 再加上 0x28 , 然后就把计算的结果作为文件读操作的起始地址。
	这就暴露了一个文件内部组织的重要细节:看来.crx文件被分割成若干个长度为 4104 字节的数据块。在文件偏移量上加 0x28 是一种
	跳过文件头部的快捷方法。
	该函数接收的第二个参数看来是它要读取的某个数据块的编号。


/*
 * 分析文件项	P245
 */
	00401a60 mov esi, ss:[esp+10]
	00401a64 add esi, 8
			 mov dword ptr ss:[esp+14], la
			 nop
			 mov eax, ds:[esi]
			 test eax, eax
			 je short 00401a9a
			 mov edx, eax
			 shl edx, 0a				# EDX左移0xA(10)位
			 sub edx, eax				# 将结果减去原来的值(存放在EAX中)
			 add edx, edx				# EDX*2
			 lea ecx, ds:[esi+14]
	00401a82 add edx, edx
			 push ecx
			 shr edx, 0a

	这段代码一开始把最新解密的数据块的起始地址加载到ESI，再给ESI加8，然后将该地址处32位的数值读入EAX。
	如果回过头看一下前面的内存转储列表，会看到第三个dword的内容是 00000001 。在这里，代码首先确认EAX不为 0 ， 然后再
	对它执行一系列有趣的算术运算。
	
	首先，将EDX左移0xA(10)位，然后将结果减去原来的值(存放在EAX中). 接着，EDX的值又和自己做了一次加法(相当于EDX*2).
	在 00401a82 处又执行了一次同样的操作，接着将EDX再右移0xA(10)位。
	一步步地执行这些操作，试着确定它们的目的.
		1. EDX左移 10, 相当于"edx = edx * 1024"
		2. EDX减去EAX的原始值(EAX存放的是未移位的EDX值).这表明实际上并不是将EDX乘以1024，需是执行"edx=edx*1024-edx",
		   等价于"edx = edx * 1023"
		3. EDX与它自己相加，这个操作执行了两次。相当于"edx=dex*4"，这意味着现在得到的是"dex=edx*4092"。
		4. EDX右移10位，相当于除以 1024 。最终的计算公式是"edx = edx * 4092 / 1024"。
	
	为什么不使用MUL将EDX乘以4092，再用DIV将得到的结果除以1024?
	答案是:像这样的代码运行起来要慢得多。MUL和DIV都是相对比较慢的，ADD、SUB和移位指令执行起来要快得多。

	用 optimize-for-small-code(优化为最小体积代码) 选项进行编译，就会使用MUL、DIV。
	用 optimize-for-fast-code(优化为执行效率最高的代码) 选项，会使用ADD SUB 移位。

	直接使用乘法和除法等算术指令会产生更短小的代码，但是执行效率会低很多。

	
	














